/*
    Author: Christopher Diggins
    License: MIT Licence 1.0
    Website: http://www.cdiggins.com
*/

#ifndef CVML_ANALYZER_HPP
#define CVML_ANALYZER_HPP

struct ByteCodeAnalyzer
{
    struct OpCodeStats
    {
        OpCodeStats() 
            : count(0), opcode(op_noop) 
        { }
        OpCodeStats(const OpCodeStats& x)
            : count(x.count), opcode(x.opcode)
        { }        
        bool operator<(const OpCodeStats& x) const {
            return count < x.count;
        }
        int count; 
        OpCodeEnum opcode;
        void Print()  {
            printf("opcode %s, count %d\n", OpCodeToPChar(opcode), count);
        }
    };

    std::map<OpCodeEnum, OpCodeStats> stats;
    std::priority_queue<OpCodeStats> queue;
    std::vector<OpCodeStats> vector;
    int count;

    ByteCodeAnalyzer()
        : count(0)
    { }

    template<typename Iter_T>
    void PushStatsToQueue(Iter_T begin, Iter_T end)
    {
        while (begin != end) 
            queue.push(begin++->second);
    }

    void Analyze(ByteCode* bc) {
        for (int i=0; i < bc->GetNumSubs(); ++i) {
            Analyze(bc->GetSub(i));
        }
        PushStatsToQueue(stats.begin(), stats.end());
        while (!queue.empty()) {
            vector.push_back(queue.top());
            queue.pop();
        }
    }

    void Analyze(Subroutine* sub) {
        Instruction* i = sub->first;
        while (i != NULL) {
            Analyze(i);
            i = i->next;
        }
    }

    void Analyze(Instruction* i) {
        stats[i->opcode].count += 1;
        stats[i->opcode].opcode = i->opcode;
        count++;
    }

    void PrintStats()  
    {
        printf("Total instructions = %d\n", count);
        size_t n = 5;
        printf("Top %d instructions\n", n);
        for (size_t i=0; i < n && i < vector.size(); ++i) {
            vector[i].Print();
        }
    }
};

#endif
